-
Notifications
You must be signed in to change notification settings - Fork 482
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[H1410101] iP #555
base: master
Are you sure you want to change the base?
[H1410101] iP #555
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good code quality mostly, just need to add header comments and rename variables to make it clear. 💯
src/main/java/catbot/CatBot.java
Outdated
private static void addSupportedCommandsToCommandMap() { | ||
CommandPattern<Integer> integerPattern = CatBotCommandPatterns.getIntegerPatternGenerator() | ||
.generate(io::indicateInvalidInteger); | ||
CommandPattern<NamedParameterMap> slashPattern = CatBotCommandPatterns.getSlashPatternGenerator() | ||
.generate(CatBotCommandPatterns.NO_DEFAULT); | ||
|
||
commands.setDefaultCommand(io::indicateInvalidCommand) | ||
.addCommand("bye", args -> io.cleanup()) | ||
.addCommand("list", args -> io.printTaskList(taskList)); | ||
|
||
// User modifying existing tasks (through IntegerPattern, and Index) | ||
BiConsumer<String, Consumer<Integer>> runIfValidIndexElseIndicateError = | ||
(args, lambda) -> integerPattern.ifParsableElseDefault(args, | ||
integer -> taskList.ifValidIndexElse(integer, | ||
lambda, | ||
invalidIndex -> io.indicateInvalidIndex(invalidIndex, taskList.getIndexBounds()) | ||
)); | ||
|
||
//noinspection SpellCheckingInspection | ||
commands.addCommand("mark", | ||
string -> runIfValidIndexElseIndicateError.accept(string, | ||
validIndex -> { | ||
taskList.markTask(validIndex-1); | ||
io.printTaskModified(taskList, validIndex); | ||
} | ||
) | ||
) | ||
.addCommand("unmark", | ||
string -> runIfValidIndexElseIndicateError.accept(string, | ||
validIndex -> { | ||
taskList.unmarkTask(validIndex-1); | ||
io.printTaskModified(taskList, validIndex); | ||
} | ||
) | ||
) | ||
.addCommand("delete", | ||
string -> runIfValidIndexElseIndicateError.accept(string, | ||
validIndex -> io.printTaskDeleted(taskList.removeTask(validIndex-1)) | ||
) | ||
); | ||
|
||
// User creating new tasks (with SlashPattern) | ||
|
||
BiConsumer<String, BiFunction<NamedParameterMap, BiConsumer<ErrorIndicatorIo.InvalidState, NamedParameterMap>, Optional<Task>>> | ||
createTaskIfValidElseWarn = (args, bifunction) -> slashPattern.ifParsableElseDefault(args, | ||
namedParameterMap -> bifunction.apply( | ||
namedParameterMap, | ||
io::indicateArgumentInvalid | ||
).ifPresent(task -> { | ||
taskList.addTask(task); | ||
io.printTaskAdded(taskList); | ||
}) | ||
); | ||
|
||
commands.addCommand("todo", | ||
args -> createTaskIfValidElseWarn.accept(args, Task.Todo::createIfValidElse) | ||
) | ||
.addCommand("event", | ||
args -> createTaskIfValidElseWarn.accept(args, Task.Event::createIfValidElse) | ||
) | ||
.addCommand("deadline", | ||
args -> createTaskIfValidElseWarn.accept(args, Task.Deadline::createIfValidElse) | ||
) | ||
; | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps you could have added this to another class like CommandMap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually spent quite a bit deliberating this, but I ended up not doing it (at least for now).
The part where I defend myself
My thought process was that I wanted to add bot-specific things in bot-specific classes; to change what commands are supported and what behaviours result from commands, my current iteration only requires that I change or even replace CatBot
(and possibly CatBotConsoleIO
) with minimal rewrite.
While there might be some merit in a CatBotCommands
class that contains this method, that would leave CatBot as a small, anaemic class (I am leaning towards this being a bad thing, but I'm not too sure of myself here).
Ultimately, I had decided that it made more sense to me to have the commands be clear from the bot description, instead of its own separate class, especially since the class would otherwise be so small as to be trivial.
The part where I stop defending myself
I definitely see an alternative that takes your considerations into account. I could rename the current file to CatBotMain
or CatBotEntrypoint
to reflect its explicit purpose as a small and trivial class, put this initialization as a protected static method of CatBotCommandLoader
, or have it be the default initialization of CatBotCommandMap
.
I'd love to hear your thoughts on why this design might be preferable, though; or if you had a different design in mind, I'd like to chew on that as well.
Regardless, thanks for the feedback!
|
||
import java.util.function.Consumer; | ||
|
||
public class CatBotCommandPatterns { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you can consider adding header comments/javadocs? For all your other classes as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup! I'll get around to it. Eventually. :')
src/main/java/catbot/Parser.java
Outdated
* @param map to store the mapping between command and argument | ||
*/ | ||
private static void parseCmdArg(String s, NamedParameterMap map) { | ||
String[] cmdArg = s.split("\\s", 2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps you can write out the variable name of cmdArg
to be in full so that it is clearer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, will do. Thanks!
src/main/java/catbot/Parser.java
Outdated
if (emptyArgument) { | ||
map.addNamedParameter("", s.trim()); | ||
} else { | ||
parseCmdArg(s, map); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that you still wrapped in curly brackets even though they are single statement!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job 💯
src/main/java/catbot/CatBot.java
Outdated
|
||
// User creating new tasks (with SlashPattern) | ||
|
||
BiConsumer<String, BiFunction<NamedParameterMap, BiConsumer<ErrorIndicatorIo.InvalidState, NamedParameterMap>, Optional<Task>>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps u can split this line into 2? I think this line has 135 characters which exceeds the 120 characters limit stated in the coding standard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, and thanks for all the nudges for coding style.
I ended up running it through a stylechecker (finally), but I appreciate the pointers!
if (this.endOfCommand == null) findCommand(); | ||
if (this.endOfCommand == -1) return retrieve(); | ||
else return retrieve().substring(0, this.endOfCommand); | ||
} | ||
|
||
public String getArgs() { | ||
if (this.endOfCommand == null) findCommand(); | ||
if (this.endOfCommand == -1) return ""; | ||
else return retrieve().substring(this.endOfCommand+1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it would be better to have the conditionals on a separate line. E.g
if (this.endOfCommand == null) {
findCommand();
}
if (retrieve() != null) | ||
this.endOfCommand = retrieve().indexOf(" "); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to have curly brackets here based on the java coding standard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job for the chatbot! I really like your usage of java.util.function in your code. Just some small coding standard problems here and there. Overall, I really like your IP.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall a nice attempt with a close adherence to the coding standars. Just a few nits here and there but generally well designed.
src/main/java/catbot/CatBot.java
Outdated
.generate(io::indicateInvalidInteger); | ||
CommandPattern<NamedParameterMap> slashPattern = CatBotCommandPatterns.getSlashPatternGenerator() | ||
.generate(CatBotCommandPatterns.NO_DEFAULT); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like how you name the variables in a greater explanatory sense
src/main/java/catbot/Parser.java
Outdated
return by(delimiter, false); | ||
} | ||
|
||
public static Parser by(String delimiter, boolean emptyArgument) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps adding javadocs for public functions might help explain their functioning in greater detail?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted! I'll probably get back to it at some point.
//endregion | ||
|
||
//region Slash Arguments Pattern | ||
private static final SlashArgumentPatternGenerator slashPatternGenerator = new SlashArgumentPatternGenerator(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps having shorter variable names may increase the readability of the code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps, but these are very infrequently used, so I thought it might have been better to make it very descriptive instead.
I'll think about it, but as of right now I'm still leaning towards my current convention, even if it results in excessively long variable names.
return s.replaceAll("(^|\n)", "$1"+prefix); | ||
} | ||
|
||
private void line() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps adding a verb in the function name might be more intuitive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch; I'll do that!
return removed; | ||
} | ||
|
||
public void ifValidIndexElse(int index, Consumer<Integer> ifValid, Consumer<Integer> otherwise) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps adding context to the variable names might communicate their purpose better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is heavily inspired by Optional
's ifPresentOrElse
(and other similar methods), and I'm trying to take it to its logical extensions; if, even with context, this does not seem intuitive enough, I'm happy to discuss about how to make it better!
# Conflicts: # src/main/java/catbot/CatBotCommandPatterns.java
# Conflicts: # Tasks.txt # src/main/java/catbot/CatBot.java # src/main/java/catbot/CatBotCommandPatterns.java # src/main/java/catbot/io/CatbotConsoleIO.java # src/main/java/catbot/task/Task.java # src/main/java/catbot/task/TaskList.java
# Conflicts: # Tasks.txt # src/main/java/catbot/bot/CatBot.java
# Conflicts: # src/main/java/catbot/io/CatBotConsoleIo.java # src/main/java/catbot/io/UserIo.java # src/main/java/catbot/task/TaskList.java
Mainly added javadocs for classes, and their constructors. Also included javadocs for all public functions. Private or protected functions were not thoroughly documented. Test classes were not fixed, and not updated for the new functionality.
Went in to be more thorough with code quality. I already wrote most of the things with code quality in mind, so this is not a very huge change. Added comments where I deliberately diverged from general code quality advice.
Assertions, but it's actually an extension.
# Conflicts: # src/main/java/catbot/io/CatBotConsoleIo.java
Code Quality, but I actually didn't do much
Especially the linguistic form of the starting word, which I did not pay attention to while coding.
For class reasons; ignore.
CatBot
You might be wondering, why would you use CatBot?
It features peak programmer syntax, like this amazing, lovable
monstrositylittle guy.Here's a snippet for your convenience:
That's right! Your 👀 do not deceive you. That is a
BiConsumer
that takes in aBiFunction
, which takes in aBiConsumer
as one of its argumentsOptional
!I bet you've never seen that many angle brackets in a row since CS2030S.